package com.wyw.hemerocallis.service.async;

import com.wyw.hemerocallis.constant.AsyncTaskStatusEnum;
import com.wyw.hemerocallis.vo.AsyncTaskInfo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * 异步任务执行监控切面
 *
 * @author Mr Wu    yewen.wu.china@gmail.com
 * <p>
 * Update History:
 * Author        Time            Content
 */
@Slf4j
@Aspect
@Component
public class AsyncTaskMonitor {

    @Autowired
    private AsyncTaskManager asyncTaskManager;

    /**
     * 异步任务执行的环绕切面
     *      环绕切面可以在方法执行前与方法执行后做一些"额外"操作
     */
    @Around("execution(* com.wyw.hemerocallis.service.async.AsyncServiceImpl.*(..))")
    public Object taskHandle(ProceedingJoinPoint proceedingJoinPoint) {
        //获取taskId，调用异步任务传入的第二个参数
        String taskId = proceedingJoinPoint.getArgs()[1].toString();
        //获取任务信息，在提交任务的时候就已经放到容器中了
        AsyncTaskInfo taskInfo = asyncTaskManager.getTaskInfo(taskId);
        log.info("AsyncTaskMonitor is monitoring async task:{}", taskId);

        taskInfo.setStatus(AsyncTaskStatusEnum.RUNNING);
        asyncTaskManager.setTaskInfo(taskInfo);//设置为运行状态，并放回容器

        AsyncTaskStatusEnum status;
        Object result;

        try {
            //执行异步任务
            result = proceedingJoinPoint.proceed();
            status = AsyncTaskStatusEnum.SUCCESS;
        } catch(Throwable ex) {
            //异步任务出现了异常
            result = null;
            status = AsyncTaskStatusEnum.FAILED;
            log.error("AsyncTaskMonitor: async task {} is failed, error info: {}",
                    taskId, ex.getMessage(), ex);
        }

        // 设置异步任务其他的信息, 再次重新放入到容器中
        taskInfo.setEndTime(new Date());
        taskInfo.setStatus(status);
        taskInfo.setTotalTime(String.valueOf(
                taskInfo.getEndTime().getTime() - taskInfo.getStartTime().getTime()
        ));
        asyncTaskManager.setTaskInfo(taskInfo);

        return result;
    }
}
